package service

import (
	"context"
	"encoding/json"
	"fx_swift_boss/api"
	"fx_swift_boss/internal/model"
	"fx_swift_boss/pkg/code"
	"fx_swift_boss/pkg/global"
	"fx_swift_boss/pkg/gorsa"
	"fx_swift_boss/pkg/internalerrors"
	"fx_swift_boss/pkg/logger"
	"fx_swift_boss/pkg/page"
	"fx_swift_boss/pkg/utils"
	"github.com/gogf/gf/v2/container/gvar"
	"github.com/gogf/gf/v2/database/gdb"
	"github.com/gogf/gf/v2/frame/g"
	"github.com/shopspring/decimal"
	"github.com/spf13/cast"
)

type ICardSrv interface {
	// 卡管理列表
	CardList(ctx context.Context, req *api.CardListReq) (*page.Collection[*api.CardListRes], error)
	// 卡详情
	GetCardDetails(ctx context.Context, cardId string) (*api.GetCardDetailsRes, error)
	// 操作卡状态
	OperatorCardState(ctx context.Context, state, cardId string) error
	// 卡交易列表
	CardTradeList(ctx context.Context, req *api.CardTradeListReq) (*page.Collection[*api.CardTradeListRes], error)
	// 宝付账户余额
	BossAccount(ctx context.Context, ccy string) (*api.BossAccountRes, error)
}
type cardSrv struct {
}

func NewCardSrv() ICardSrv {
	return &cardSrv{}
}

// 卡管理列表
func (c *cardSrv) CardList(ctx context.Context, req *api.CardListReq) (*page.Collection[*api.CardListRes], error) {
	var (
		err        error
		resultList []*api.CardListRes
		total      int
	)

	collectionDto := &page.Collection[*api.CardListRes]{}
	collectionDto.Page = req.Page
	collectionDto.PageSize = req.PageSize

	mod := global.GFDB.Ctx(ctx).Schema("card").Model("fx_card_info fci")
	mod.LeftJoin("fx_enterprise_account_apply fea", "fci.account=fea.account")
	mod.LeftJoin("fx_cardholder fc", "fci.card_user_id=fc.card_user_id")
	mod.Fields("fci.card_no,fci.balance_amt as balance,fc.first_name,fc.last_name," +
		"fci.expiration,fci.create_card_time,fci.card_status as state,fea.company_name,fci.card_id")
	if len(req.CardNo) > 0 {
		mod.WhereLike("fci.card_no", "%"+req.CardNo+"%")
	}
	if len(req.CompanyName) > 0 {
		mod.WhereLike("fea.company_name", "%"+req.CompanyName+"%")
	}
	if len(req.Name) > 0 {
		mod.WhereLike("concat(fc.first_name,fc.last_name)", "%"+req.Name+"%")
	}
	if len(req.StartTime) > 0 && len(req.EndTime) > 0 {
		mod.Where("fci.create_card_time >=? and fci.create_card_time < ?", req.StartTime+" 00:00:00", req.EndTime+" 23:59:59")
	}
	if len(req.SortFields) > 0 && len(req.SortMethod) > 0 {
		mod.Order("fci." + req.SortFields + " " + req.SortMethod)
	}
	mod.Order("fci.create_card_time desc")
	mod.Limit(int(page.PageToOffset(req.Page, req.PageSize)), cast.ToInt(req.PageSize))
	err = mod.ScanAndCount(&resultList, &total, false)
	collectionDto.TotalPage = page.GetTotalPage(req.Page, req.PageSize, cast.ToInt64(total))

	if err != nil {
		return nil, internalerrors.New(code.ErrUnknown, "数据查询异常")
	}
	collectionDto.Total = cast.ToInt64(total)
	collectionDto.List = resultList

	return collectionDto, err
}

// 卡详情
func (c *cardSrv) GetCardDetails(ctx context.Context, cardId string) (*api.GetCardDetailsRes, error) {
	type DbVo struct {
		CardId       string `json:"card_id"`
		CardUserId   string `json:"card_user_id"`
		CardNo       string `json:"card_no"`
		CardStatus   string `json:"card_status"`
		BalanceAmt   string `json:"balance_amt"`
		CardAlias    string `json:"card_alias"`
		Expiration   string `json:"expiration"`
		CardVerifyNo string `json:"card_verify_no"`
		Email        string `json:"email"`
	}
	var (
		err             error
		dbVo            *DbVo
		cardTradeDbList []*model.FxCardTradeRecord
		cardTreadList   = make([]*api.CardTradeList, 0)
		cardHolderObj   model.FxCardholder
		result          = &api.GetCardDetailsRes{}
		finalBalance    float64
		redisResult     *gvar.Var
	)
	err = requestCardInfo(cardId)

	if err = global.GFDB.Ctx(ctx).Schema("card").Model("fx_card_info").
		Where("card_id=?", cardId).Scan(&dbVo); err != nil {
		logger.SugarLogger.Error(err)
		return nil, internalerrors.New(code.ErrUnknown, "读取数据异常")
	}
	if dbVo == nil {
		return nil, internalerrors.New(code.ErrUnknown, "卡号异常")
	}
	if len(dbVo.CardUserId) > 0 {
		// 获取持卡人账单地址
		if err = global.GFDB.Ctx(ctx).Schema("card").Model("fx_cardholder").
			Where("card_user_id=?", dbVo.CardUserId).Scan(&cardHolderObj); err != nil {
			return nil, internalerrors.New(code.ErrUnknown, err.Error())
		}

		if err = global.GFDB.Ctx(ctx).Schema("card").Model("fx_card_trade_record").
			Where("card_id=?", cardId).Order("occur_time desc").Limit(10).Scan(&cardTradeDbList); err != nil {
			return nil, internalerrors.New(code.ErrUnknown, err.Error())
		}
	}

	if len(cardTradeDbList) > 0 {
		for _, value := range cardTradeDbList {
			cardTreadList = append(cardTreadList, &api.CardTradeList{
				TradeTime:    value.OccurTime,
				Amount:       value.TransCurrencyAmt,
				MerchantName: value.MerchantName,
				TradeType:    value.TransType,
				State:        value.TransStatus,
			})
		}
		result.CardTradeList = cardTreadList
	}
	// 判断改cardId是否有过欠费
	redisResult, err = g.Redis().Get(ctx, cardId+"-arrearsBalance")
	if err != nil {
		logger.SugarLogger.Error(err.Error())
		return nil, internalerrors.New(code.ErrUnknown, err.Error())
	}
	if redisResult.Val() != nil {
		finalBalance = cast.ToFloat64(dbVo.BalanceAmt) - redisResult.Float64()
	} else {
		finalBalance = cast.ToFloat64(dbVo.BalanceAmt)
	}

	result.CardId = dbVo.CardId
	result.State = dbVo.CardStatus
	result.CardNo = dbVo.CardNo
	result.LastFourNum = dbVo.CardNo[len(dbVo.CardNo)-4:]
	result.Balance = cast.ToString(finalBalance)
	result.FirstName = cardHolderObj.FirstName
	result.LastName = cardHolderObj.LastName
	result.BillAddress = cardHolderObj.BillingAddress + " " + cardHolderObj.BillingCity + " " + cardHolderObj.BillingState + " " + cardHolderObj.BillingZipCode
	result.Email = dbVo.Email
	result.CardAlias = dbVo.CardAlias
	result.CardVerifyNo = dbVo.CardVerifyNo
	result.Expiration = dbVo.Expiration
	return result, nil
}

// 操作卡状态
func (c *cardSrv) OperatorCardState(ctx context.Context, state, cardId string) error {
	var (
		err          error
		cardInfoObj  *model.FxCardInfo
		account      string
		freezeRecord *model.FxFreezeRecord
	)
	account = ctx.Value("Account").(string)
	if err = global.GFDB.Ctx(ctx).Schema("card").Model("fx_card_info").Where("card_id=?", cardId).
		Scan(&cardInfoObj); err != nil {
		return internalerrors.New(code.ErrUnknown, "数据查询异常")
	}
	if state == "0" { // 需要冻结
		err = EditCardStatus(ctx, &api.EditCardStatusReq{
			CardId:    cardId,
			Status:    state,
			UserReqNo: utils.GetHashCode(utils.GenerateCode32()),
		})
		if err != nil {
			return internalerrors.New(code.ErrUnknown, err.Error())
		}
		db := g.DB().Schema("card")
		err = db.Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {
			_, err = tx.Model("fx_freeze_record").Insert(&model.FxFreezeRecord{
				CardId:       cardId,
				Account:      account,
				OperatorType: "boss",
				Operator:     state,
			})
			if err != nil {
				logger.SugarLogger.Error(err)
				return internalerrors.New(code.ErrUnknown, "冻结操作记录异常")
			}
			return nil
		})
	} else if state == "1" { // 需要解冻
		if err = global.GFDB.Ctx(ctx).Schema("card").Model("fx_freeze_record").
			Where("card_id=? and operator='0'", cardId).
			Order("created_at desc").Limit(1).
			Scan(&freezeRecord); err != nil {
			return internalerrors.New(code.ErrUnknown, "操作记录查询异常")
		}
		err = EditCardStatus(ctx, &api.EditCardStatusReq{
			CardId:    cardId,
			Status:    state,
			UserReqNo: utils.GetHashCode(utils.GenerateCode32()),
		})
		if err != nil {
			return internalerrors.New(code.ErrUnknown, "操作卡状态异常")
		}
		db := g.DB().Schema("card")
		err = db.Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {
			_, err = tx.Model("fx_freeze_record").Insert(&model.FxFreezeRecord{
				CardId:       cardId,
				Account:      account,
				OperatorType: "boss",
				Operator:     state,
			})
			if err != nil {
				logger.SugarLogger.Error(err)
				return internalerrors.New(code.ErrUnknown, "解冻结操作记录异常")
			}
			return nil
		})
	}
	return nil
}

// 卡交易列表
func (c *cardSrv) CardTradeList(ctx context.Context, req *api.CardTradeListReq) (*page.Collection[*api.CardTradeListRes], error) {
	var (
		err        error
		resultList []*api.CardTradeListRes
		total      int
	)
	collectionDto := &page.Collection[*api.CardTradeListRes]{}
	collectionDto.Page = req.Page
	collectionDto.PageSize = req.PageSize

	mod := global.GFDB.Ctx(ctx).Schema("card").Model("fx_card_trade_record fa").
		LeftJoin("fx_card_info fc", "fa.card_id=fc.card_id").
		LeftJoin("fx_cardholder fch", "fc.card_user_id=fch.card_user_id").
		LeftJoin("fx_enterprise_account_apply fea", "fea.account=fc.account")
	mod.Fields("fa.card_id,fa.record_no as trade_no,fc.card_no,fc.card_alias,fch.first_name,fch.last_name,fa.trans_currency_amt as amount," +
		"fa.local_currency_amt as local_amount,fa.trans_type as trade_type,fa.created_at as trade_time,fa.trans_status as state,fa.merchant_name,fea.company_name,fa.trans_currency as currency,fa.local_currency as local_currency")
	if len(req.CardNo) > 0 {
		mod.WhereLike("fc.card_no", "%"+req.CardNo+"%")
	}
	if len(req.TradeType) > 0 {
		mod.Where("fa.trans_type=?", req.TradeType)
	}
	if len(req.CompanyName) > 0 {
		mod.Where("fea.company_name", req.CompanyName)
	}
	if len(req.StartTime) > 0 && len(req.EndTime) > 0 {
		mod.Where("fa.created_at >=? and fa.created_at <=?", req.StartTime+" 00:00:00", req.EndTime+" 23:59:59")
	}
	if len(req.TradeNo) > 0 {
		mod.WhereLike("fa.record_no", "%"+req.TradeNo+"%")
	}
	if len(req.State) > 0 {
		mod.Where("fa.trans_status=?", req.State)
	}
	if len(req.SortFields) > 0 && len(req.SortMethod) > 0 {
		mod.Order("fa." + req.SortFields + " " + req.SortMethod)
	}
	mod.Order("fa.created_at desc")
	mod.Limit(int(page.PageToOffset(req.Page, req.PageSize)), cast.ToInt(req.PageSize))
	err = mod.ScanAndCount(&resultList, &total, false)
	collectionDto.TotalPage = page.GetTotalPage(req.Page, req.PageSize, cast.ToInt64(total))

	if err != nil {
		return nil, internalerrors.New(code.ErrUnknown, "数据查询异常")
	}
	collectionDto.Total = cast.ToInt64(total)
	collectionDto.List = resultList

	return collectionDto, err
}

// 宝付账户余额
func (c *cardSrv) BossAccount(ctx context.Context, ccy string) (*api.BossAccountRes, error) {
	var (
		err            error
		url            = "/api/user/account/queryUserBalanceAccount"
		dataContent    string
		pubdecrypt_str string
		resp           *api.BossAccountInfoRes
		result         = &api.BossAccountRes{}
		accountObj     *model.FxAccount
	)
	dataContent, err = OperatorParams(global.ViperObj.GetString("gep.url")+url, &api.BossAccountReq{
		Ccy: ccy,
	})
	if err != nil {
		return nil, internalerrors.New(code.ErrUnknown, err.Error())
	}
	// 公钥解密
	pubdecrypt_str, err = gorsa.PublicDecrypt(dataContent, gorsa.GetPublicKeyStr())
	if err != nil {
		return nil, internalerrors.New(code.ErrUnknown, err.Error())
	}
	err = json.Unmarshal([]byte(pubdecrypt_str), &resp)
	if err != nil {
		return nil, internalerrors.New(code.ErrUnknown, err.Error())
	}

	if err = global.GFDB.Ctx(ctx).Schema("card").Model("fx_account").
		Where("account='admin'").Scan(&accountObj); err != nil {
		return nil, internalerrors.New(code.ErrUnknown, err.Error())
	}

	//统计代理商余额总和
	var agentResult struct {
		AgentBalance decimal.Decimal `json:"agentBalance"`
	}
	if err = global.GFDB.Ctx(ctx).Schema("card").Model("fx_account").Fields("SUM(balance) as agentBalance").Where("account !='admin'").Scan(&agentResult); err != nil {
		return nil, internalerrors.New(code.ErrUnknown, err.Error())
	}
	result.Cyy = resp.Cyy
	result.AvailableBal = cast.ToString(resp.AvailableBal)
	//result.CurrentBalance = cast.ToString(resp.CurrentBalance)
	//result.Balance = cast.ToString(accountObj.Balance)
	result.Balance = cast.ToString(0) // 暂时设置为0
	result.AgentBalance = cast.ToString(agentResult.AgentBalance)
	return result, err
}

func requestCardInfo(cardId string) error {
	var (
		err            error
		url            = "/api/vas/card/info"
		dataContent    string
		pubdecrypt_str string
		resp           *api.CardInfoRes
		cardInfoObj    = &model.FxCardInfo{}
	)
	dataContent, err = OperatorParams(global.ViperObj.GetString("gep.url")+url, &api.GetCardInfoReq{
		CardId: cardId,
	})
	if err != nil {
		return internalerrors.New(code.ErrUnknown, err.Error())
	}
	// 公钥解密
	pubdecrypt_str, err = gorsa.PublicDecrypt(dataContent, gorsa.GetPublicKeyStr())
	if err != nil {
		return internalerrors.New(code.ErrUnknown, err.Error())
	}
	err = json.Unmarshal([]byte(pubdecrypt_str), &resp)
	if err != nil {
		return internalerrors.New(code.ErrUnknown, err.Error())
	}
	if err = global.GFDB.Schema("card").Model("fx_card_info").
		Where("card_id=?", cardId).
		Scan(&cardInfoObj); err != nil {
		return internalerrors.New(code.ErrUnknown, err.Error())
	}
	if len(pubdecrypt_str) > 0 {
		if _, err = global.GFDB.Schema("card").Model("fx_card_info").Data(g.Map{
			"start_active_date":     resp.StartActiveDate,
			"end_close_date":        resp.EndCloseDate,
			"credit_limit_amt":      resp.CreditLimitAmt,
			"min_auth_amt":          resp.MinAuthAmt,
			"max_auth_amt":          resp.MaxAuthAmt,
			"balance_amt":           resp.BalanceAmt,
			"used_auth_amt":         resp.UsedAuthAmt,
			"enable_multi_use":      resp.EnableMultiUse,
			"enable_currency_check": resp.EnableCurrencyCheck,
			"card_closed_amt":       resp.CardClosedAmt,
			"card_status":           resp.CardStatus,
			"card_status_desc":      resp.CardStatusDesc,
			"create_card_time":      resp.CreateTime,
			"card_alias":            resp.CardAlias,
		}).Where("card_id=?", cardId).Update(); err != nil {
			return internalerrors.New(code.ErrUnknown, err.Error())
		}
	}
	return err
}
